# encoding: UTF-8

"""
本文件包含了策略开发用类模板。
策略只需根据历史数据和即时数据计算相关指标、交易信号（开多、平多、开空、平空，也可能有止损价位），
并将得到的交易信号送到相关引擎（策略引擎、测试引擎、回测引擎）的事件中，供风险引擎调用。
该类包含的重要属性和方法：
属性：
paramNameList

方法：

"""
import multiprocessing

from config.system_conf import bq_log
from engine.strategy_engine import *
from utils.function import str_datetime

# 开仓方向
OPEN_DIRECTION_LONG = 'LONG'
OPEN_DIRECTION_SHORT = 'SHORT'
OPEN_DIRECTION_BOTH = 'BOTH'

"""策略模板
provide the following methods:
on_init(params=None,other_setting=None): 
    初始化策略，必须由具体策略继承实现,并要调用此父函数, 由策略引擎调用
    在此可以设置交易标的，调入参数，优化参数，设置止损方法，
    调入历史数据、计算相关指标
    
on_start: 确保策略事件引擎可用，注册相关事件()，由策略引擎调用，
on_stop: 注销相关事件，由策略引擎调用
on_tick: 收到Tick数据时执行
on_ticks: 收到历史Tick数据序列时执行
on_bar: 收到K线数据时执行
on_bars: 收到历史K线数据序列时执行
on_optimize: 要求优化时执行

req_bars
req_ticks
req_params

===============
buy: open long
sell: close long
short: open short
cover: close short
send_order: send the order to strategy_event_engine

"""


def calc_long_signal(cls, data, params):
    """
    类级方法：计算做多信号,当做多头回测时调用，由具体策略实现
    :param data:
    :param params:参数字典：{参数名称：参数值}，包含'period':PERIOD_TYPE_TICK
    :return:pd.DataFrame(columns=['tprice','buy','sell'],index='datetime')
    """
    print('IStrategy.calc_long_signal')


def calc_short_signal(cls, data, params):
    """
    类级方法：计算做空信号,当做空头回测时调用，由具体策略实现
    :param data:
    :param params:
    :return:pd.DataFrame(columns=['tprice','short','cover'],index='datetime')
    """
    print('IStrategy.calc_short_signal')


def calc_long_short_signal(cls, data, params):
    """
    类级方法：计算多空信号，当做多、空回测时调用，由具体策略实现
    :param data:
    :param params:
    :return:pd.DataFrame(columns=['tprice','buy','sell','short','cover'],index='datetime')
    """
    print('IStrategy.calc_long_short_signal')
    rslt = {}
    rslt['long'] = cls.calc_long_signal(data, params)
    rslt['short'] = cls.calc_short_signal(data, params)
    return rslt


def run_param_optimization(cls, data, params):
    """
    类级方法：参数优化
    :param data: 供优化的数据
    :param params:{name:{default:1,min:1,max:2,step:1,multiplier:1,description:''}}
    {name:[min,max,step]}
    :return:
    """


# 策略类的名称和作者
strategy_class_name = "IStrategy"
author = EMPTY_UNICODE

strategy_type = FORMULA_TYPE_STRATEGY
period = PERIOD_TYPE_TICK  #

#
# 策略的基本参数
instance_name = 'IStrategy_instrument_id_period'  # 策略实例名称，正常构成形式：class_name_instrument_id_period
symbol = EMPTY_STRING  # 交易的合约代码
instrument_id = EMPTY_STRING
currency = EMPTY_STRING  # 货币（只有IB接口需要）

# 策略的基本变量，由引擎管理
inited = False  # 是否进行了初始化
_trading = False  # 是否启动交易，由引擎管理
running = False  # 是否运行策略，由引擎管理
pos = 0  # 持仓情况,0＝无持仓，正数＝持多头，负数＝持空头

# 参数列表，保存了参数的名称
param_name_list = []
params = {}  # 参数字典
variables = {}  # 变量字典
# 变量
buy_cond = 1  # 看多条件
sell_cond = 2  # 平多条件
short_cond = 2  # 看空条件
cover_cond = 1  # 平空条件
open_direction = OPEN_DIRECTION_BOTH
strategy_event_engine = None
data_event_engine = None

# 当前日期,格式：yyyy-MM-dd 00:00:00, 类型：datetime
today = today_date()
start_datetime = str_datetime(dttm=-30)  # 确定参数（回测）的开始日期时间，默认为当前回溯30天格式：yyyyMMdd 00:00:00  %Y%m%d %H:%M:%S
end_datetime = str_datetime()  # 确定参数（回测）所需数据的结束日期时间，默认为当下，格式：yyyyMMdd 00:00:00

# 策略基础周期
baseperiod = PERIOD_TYPE_TICK
params = {}  # 计算指标用到的参数列表，key为参数名称，值为：StrategyParam

# 策略滑点
slippage = 0
# 策略当前信号
current_strategy_signal = StrategySignal()
strategy_signals_count = EMPTY_INT
# 输出列名
out_columns = ['close', 'buy', 'sell', 'short', 'cover', 'vol', 'trade_price']
out_data = pd.DataFrame(columns=out_columns)

# 策略信号序列字典，日期时间是Key,策略信号是Value
strategy_signals = {}
buy_series = pd.Series()  # 开多仓信号序列
sell_series = pd.Series()  # 平多仓信号序列
short_series = pd.Series()  # 开空仓信号序列
cover_series = pd.Series()  # 平空仓信号序列

may_buy = True  # 当前状态，可以开多或者平空
may_sell = True  # 当前状态，可以开空或者平多
may_add = False  # 当前状态，可加仓
# 变量列表，保存了变量的名称
var_list = ['inited',
            'trading',
            'pos',
            'lc',
            'sc',
            'buy',
            'sell',
            'short',
            'cover']


def init(setting, strategy_event_engine=None, open_direction=OPEN_DIRECTION_BOTH, data_event_engine=None):
    """
    :param strategy_event_engine: 可能是交易用的 StrategyEngine, 也可能是测试用的StrategyTestEngine，
    还可能是回测用的 BacktestEngine
    :param setting:具体策略实例的参数字典{setting_name:default_value},至少要有symbol
    :param open_direction: 可开仓方向
    :param data_event_engine: 数据引擎，提供行情和历数数据的
    """

    if setting:
        if 'symbol' in setting:
            symbol = setting['symbol']
        d = __dict__
        # print(d)
        for key in param_name_list:
            if key in setting.keys():
                d[key] = setting[key]
        instance_name = '_'.join([strategy_class_name, symbol, str(baseperiod)])


def register(data_event_engine):
    data_event_engine = data_event_engine
    data_event_engine.register(EVENT_RSP_TICKS + symbol, on_ticks)
    data_event_engine.register(EVENT_RSP_BARS + symbol, on_bars)


def set_instrument_id(instrument_id):
    """设置交易标的"""
    instrument_id = instrument_id
    symbol = instrument_id
    instance_name = '_'.join([strategy_class_name, symbol, str(baseperiod)])


def set_strategy_engine(strategy_event_engine):
    strategy_event_engine = strategy_event_engine


def set_pos(pos):
    """
    设置持仓，<0:空仓，>0: 多仓，=0：持币，实盘时用，
    :param pos:
    :return:
    """
    pos = pos
    if pos == 0:
        may_buy = True
        may_sell = True
    elif pos > 0:
        may_sell = True
        may_buy = False
        if may_add:
            may_buy = True
    else:
        may_buy = True
        may_sell = False
        if may_add:
            may_sell = True


def name():
    """设置并返回策略实例名称"""
    return instance_name


def on_init(params=None):
    """初始化策略，必须由用户继承实现,并要调用此父函数
    调用此函数前要保证 strategy_engine is not None
    在此可以调入参数及历史数据，优化参数，设置止损方法
    根据选中的参数及历史数据计算指标值
    """


def on_start(self):
    """启动策略（必须由用户继承实现）
    Start the order-tick-k-bar-data-event and
     the calculate-indicators-event to
    define the new strategic signal
    """


def on_stop(self):
    """停止策略（必须由用户继承实现）

    """
    running = False

    # 注销事件
    # data_event_engine.unregister(EVENT_TICK + symbol, on_tick)


def on_tick(tick):
    """收到行情TICK推送（必须由用户继承实现）
    利用新的tick数据，计算相关指标，并判断是否有交易信号产生"""
    raise NotImplementedError


def on_ticks(ticks):
    """收到历史行情TICKs推送,used by backtest
    （必须由用户继承实现）"""
    raise NotImplementedError


def on_tick_event(event):
    """ called  by data_server or BarDataFrame """
    tick = event.dict_['data']
    on_tick(tick)


def on_ticks_event(event):
    """ called  by BarDataFrame"""
    ticks = event.dict_['data']
    on_ticks(ticks)


def on_bar(bar):
    """收到Bar推送（必须由用户继承实现）"""
    raise NotImplementedError


def on_bars(bars):
    """收到历史Bars推送（必须由用户继承实现）
    used by backtest
    计算所有用到的指标
    """
    raise NotImplementedError


def on_bar_event(event):
    """收到Bar推送 """
    bar = event.dict_['data']
    on_bar(bar)


def on_bars_event(event):
    """收到历史Bars推送
    used by backtest
    计算所有用到的指标
    """
    bars = event.dict_['data']
    on_bars(bars)


def buy(price, volume, stop_price=EMPTY_FLOAT, stop=False, dt=None, strategy_instance_name=None):
    """买开=OpenLong"""
    # strategyEngine.openLong(vtSymbol, price, volume)
    if not dt:
        dt = datetime.datetime.now()
    send_order(STRATEGY_ORDER_BUY, price, volume, stop_price, stop, dt, strategy_instance_name)
    set_pos(pos + volume)


def sell(price, volume, stop_price=EMPTY_FLOAT, stop=False, dt=None, strategy_instance_name=None):
    """卖平=CloseLong"""
    # strategyEngine.closeLong(vtSymbol, price, volume)
    if not dt:
        dt = datetime.datetime.now()
    send_order(STRATEGY_ORDER_SELL, price, volume, stop_price, stop, dt)
    set_pos(pos - volume)


def short(price, volume, stop_price=EMPTY_FLOAT, stop=False, dt=None):
    """卖开=OpenShort"""
    # strategyEngine.openShort(vtSymbol, price, volume)
    if not dt:
        dt = datetime.datetime.now()
    send_order(STRATEGY_ORDER_SHORT, price, volume, stop_price, stop, dt)
    set_pos(pos - volume)


def cover(price, volume, stop_price=EMPTY_FLOAT, stop=False, dt=None):
    """买平=CloseShort"""
    # strategyEngine.closeShort(vtSymbol, price, volume)
    send_order(STRATEGY_ORDER_COVER, price, volume, stop_price, stop, dt)
    set_pos(pos + volume)


def send_order(order_type, price, volume, stop_price=EMPTY_FLOAT, stop=False, dt=None,
               strategy_instance_name=''):
    # print("""发送委托 from strategy""")
    ss = StrategySignal()
    ss.datetime = dt
    ss.symbol = symbol
    ss.name = instance_name
    ss.price = price
    ss.vol = volume
    ss.order_type = order_type
    ss.params = params
    ss.stop_price = stop_price

    now = datetime.now().strftime('%Y%m%d %H:%M:%S.%f')
    strategy_signals[now] = ss
    event = Event(event_type=EVENT_STRATEGY_SIGNAL + strategy_instance_name, dict_={'data': ss})

    strategy_event_engine.put(event)


def rq_params(self):
    """读取策略参数
    参数放在 config/strategy_params.json中
    以策略类名、实例名为key"""
    # print(className, symbol)
    event = Event(event_type=EVENT_REQ_PARAMS, dict_={'data': instance_name})
    data_event_engine.put(event)
    # params = strategy_engine.get_params(instance_name)


def rq_ticks(start_datetime, end_datetime, days=10):
    """读取tick数据"""
    # ticks = strategy_engine.load_tick(symbol, days=days)
    # on_ticks(ticks)
    event = Event(event_type=EVENT_REQ_TICKS, dict_={'symbol': symbol,
                                                     'start_datetime': start_datetime,
                                                     'end_datetime': end_datetime})
    data_event_engine.put(event)


def req_log(content):
    """记录CTA日志"""
    content = instance_name + ':' + content
    strategy_event_engine.req_log(content)


def put_event(strategy_event_engine, event):
    """发出策略状态变化事件"""
    strategy_event_engine.put(event)


def calc_signal(data, params):
    """
    计算策略信号，由具体策略实现
    :param data:pd.DataFrame 计算信号要用到的数据，如果是 Tick 类数据，包含datetime,lastPrice,volume;
    如果是Bar类数据，包含datetime,open,high,low,close,volume
    :param params: 计算信号用到的参数字典，参数名称：值
    :return:pd.DataFrame, 在data中增加：buy,sell, short, cover 标志列
    """


def calc_result(data, long_short=0):
    """
    回测时用，计算策略的统计结果
    :param data:交易序列，类型：pd.DataFrame,包含日期时间（datetime)、收盘价格（close）、
                交易价格(price)、开多(buy)、平多(sell)、开空(short)、平空(cover)、交易量(vol)
    :param long_short: 1=long,-1=short,0=both
    :return:
    """
    rslt = 1

    return data


def run_parallel_optimization(data, optimizationSetting):
    """并行优化参数"""
    # 获取优化设置
    settingList = optimizationSetting.generate_setting()
    targetName = optimizationSetting.optimizeTarget

    # 检查参数设置问题
    if not settingList or not targetName:
        output('优化设置有问题，请检查')

    # 多进程优化，启动一个对应CPU核心数量的进程池
    pool = multiprocessing.Pool(multiprocessing.cpu_count())
    l = []

    # for setting in settingList:
    #     l.append(pool.apply_async(on_optimize, ( setting,
    #                                                  targetName, mode,
    #                                                  start_datetime, initDays, end_datetime,
    #                                                  slippage, rate, size,
    #                                                  dbName, symbol)))
    pool.close()
    # pool.join()

    # 显示结果
    resultList = [res.get() for res in l]
    resultList.sort(reverse=True, key=lambda result: result[1])
    output('-' * 30)
    output(u'优化结果：')
    for result in resultList:
        output(u'%s: %s' % (result[0], result[1]))


def on_optimize(strategyClass, setting, targetName,
                mode, startDate, initDays, endDate,
                slippage, rate, size,
                dbName, symbol):
    """多进程优化时跑在每个进程中运行的函数"""
    # account_engine = TradeEngine()
    # engine = BacktestEngine(account_engine)
    # engine.setBacktestingMode(mode)
    # engine.setStartDate(startDate, initDays)
    # engine.setSlippage(slippage)
    # engine.setRate(rate)
    # engine.setSize(size)
    # engine.setDatabase(dbName, symbol)
    #
    # engine.initStrategy(strategyClass, setting)
    # engine.runBacktesting()
    # d = engine.calculateBacktestingResult()
    # try:
    #     targetValue = d[targetName]
    # except KeyError:
    #     targetValue = 0
    # return (str(setting), targetValue)


def output(msg):
    """"""


class IStrategy:
    """策略接口"""
    # 策略的基本变量，由引擎管理

    _inited = False  # 是否进行了初始化
    _trading = False  # 是否启动交易，由引擎管理
    _running = False  # 是否运行策略，由引擎管理
    pos = 0  # 持仓情况,0＝无持仓，正数＝持多头，负数＝持空头,20000000=双向持仓
    symbol = ''
    baseperiod = PERIOD_TYPE_TICK
    may_add = False  # 可以加仓
    may_buy = True  # 可以开多
    may_sell = False  # 可以平多
    may_short = True  # 可以开空
    may_cover = False  # 可以平空
    bs = 0  # buy=1,sell=-1
    sc = 0  # short=1,cover=-1
    bsscs = [0]  # 0: money, 1:= buy, -1:= sell, -2:= short, 2:= cover, 4:= cover and buy, -4:= sell and short
    strategy_signals = {}  # 策略信号 '%Y%m%d %H:%M:%S.%f' ： StrategySignal
    data = None
    data_len = 200

    def __init__(self, stra_event_engine, params=None, setting=None, data_engine=None):
        self.event_engine = stra_event_engine
        if not strategy_event_engine:
            self.event_engine = IStrategyEngine()
            self.event_engine.start()
        self.data_engine = data_engine
        self.params = params
        self.instance_name = '_'.join(
            [self.__class__.__name__, self.symbol, str(self.baseperiod)])  # 'class_name_symbol_periods'
        self.min_data_len = 100
        self.vars = {}
        self.start_datetime = datetime.datetime.now() - datetime.timedelta(days=5)
        self.end_datetime = datetime.datetime.now()
        self.setting = setting
        if setting:
            d = self.__dict__
            for k, v in setting.items():
                d[k] = v

    def to_signals(self, bsscs=None):
        """将生成的"""
        if bsscs:
            self.bsscs = bsscs
        else:
            bsscs = self.bsscs
        for index in bsscs.index:
            signal = StrategySignal()

    def set_pos(self, pos):
        """
        设置持仓，<0:空仓，>0: 多仓，=0：持币，实盘时用，
        :param pos:
        :return:
        """
        self.pos = pos
        if pos == 0:
            self.may_buy = True
            self.may_short = True
        elif pos > 0:
            self.may_sell = True
            self.may_buy = False
            if self.may_add:
                self.may_buy = True
        else:
            self.may_buy = True
            self.may_sell = False
            if self.may_add:
                self.may_sell = True

    @property
    def name(self):
        """设置并返回策略实例名称"""
        return self.instance_name

    def on_init(self, params=None, stra_engine=None, data_engine=None):
        """初始化策略，必须由用户继承实现,并要调用此父函数
        调用此函数前要保证 self.strategy_engine is not None
        在此可以调入参数及历史数据，优化参数，设置止损方法
        根据选中的参数及历史数据计算指标值
        """

        if self._inited:
            self.req_log('请勿重复初始化策略实例：%s' % self.instance_name)
            return

        self._inited = False
        # 调入参数
        if params:
            self.params = params

        # 优化参数

        # 设置止损方法

        # 调入历史数据，计算相关指标：对于回测同时计算策略信号

        # print('strategyTemplate', self.symbol)
        if stra_engine:
            self.event_engine = stra_engine
        if data_engine:
            self.data_engine = data_engine
        if not self.event_engine:
            bq_log.cri(f'{self.instance_name}: 必须有可用的策略事件引擎!')
            return
        self._inited = True

    def req_ticks(self, data_engine, data_len=200):
        '''called by out of the strategy'''
        if self.symbol == '':
            bq_log.error(f'symbol must not be empty in strategy:{self.name} ')
            return
        evt = Event(event_type=EVENT_REQ_TICKS)
        evt.dict_['data'] = {'symbol': self.symbol, 'data_len': data_len}
        data_engine.put(evt)

    def req_bars(self, data_engine, duration=0, data_len=200):
        '''called by out of the strategy'''
        if self.symbol == '':
            bq_log.error('symbol must not b empty in a strategy')
            return
        drt = duration
        if self.baseperiod == 0:
            if duration == 0:
                self.req_ticks(data_engine, data_len)
                return
        elif duration == 0:
            self.req_ticks(data_engine, data_len)
            drt = self.baseperiod
        evt = Event(event_type=EVENT_REQ_BARS)
        evt.dict_['data'] = {'symbol': self.symbol, 'duration': drt, 'data_len': data_len}
        data_engine.put(evt)

    def on_start(self, data=None):
        """启动策略（必须由用户继承实现）
        Start the order-tick-k-bar-data-event and
         the calculate-indicators-event to
        define the new strategic signal
        """
        # 保证启动前策略已经初始化
        if not self._inited:
            self.on_init()
            time.sleep(1)

        if not self._inited:
            bq_log.error(f'{self.instance_name}: 还没有初始化！')
            return
        if self._running:
            return
        else:
            if self.symbol == '' or self.symbol is None:
                bq_log.cri(f'strategy: {self.instance_name}: must have symbol to start')
                return
            if not self.data_engine:
                bq_log.cri(f'{self.instance_name}: 要进行实盘交易或者测试，必须提供数据引擎！')
                return
            if data:
                self.data = data
            self._running = True

        # 注册行情事件
        if self.symbol:
            self.event_engine.add_strategy_symbol(self.symbol)
            if self.baseperiod == PERIOD_TYPE_TICK:
                self.data_engine.register(EVENT_TICK + self.symbol, self.on_tick_event)
            else:
                self.data_engine.register(EVENT_BAR + self.symbol, self.on_bar_event)

    def on_stop(self):
        """停止策略（必须由用户继承实现）

        """
        self._running = False

        # 注销事件
        if self.baseperiod == PERIOD_TYPE_TICK:
            self.data_engine.unregister(EVENT_TICK + self.symbol, self.on_tick_event)
        else:
            self.data_engine.unregister(EVENT_BAR + self.symbol, self.on_bar_event)

    def on_tick(self, tick):
        """收到行情TICK推送（必须由用户继承实现）
        利用新的tick数据，计算相关指标，并判断是否有交易信号产生"""
        raise NotImplementedError

    def on_ticks(self, ticks, **params):
        """收到历史行情TICKs推送,used by backtest
        （必须由用户继承实现）"""
        if self.baseperiod != PERIOD_TYPE_TICK:
            return

    def on_tick_event(self, event):
        """ called  by data_server or BarDataFrame """
        tick = event.dict_['data']
        self.on_tick(tick)

    def on_ticks_event(self, event):
        """ called  by BarDataFrame"""
        ticks = event.dict_['data']
        self.on_ticks(ticks)

    def on_order(self, event):
        """收到委托变化推送（必须由用户继承实现）"""
        data = event.dict_['data']
        bq_log.info(f'收到委托：{data.__dict__}')

    def on_trade(self, event):
        """收到成交推送（必须由用户继承实现）"""
        data = event.dict_['data']
        bq_log.info(f'收到成交：{data.__dict__}')

    def on_bar(self, bar):
        """收到Bar推送（必须由用户继承实现）"""
        raise NotImplementedError

    def on_bars(self, bars, **params):
        """收到历史Bars推送（必须由用户继承实现）
        used by backtest
        计算所有用到的指标,历史策略信号
        """
        if self.baseperiod == PERIOD_TYPE_TICK:
            return

    def on_bar_event(self, event):
        """收到Bar推送 """
        bar = event.dict_['data']
        self.on_bar(bar)

    def on_bars_event(self, event):
        """收到历史Bars推送
        used by backtest
        计算所有用到的指标
        """
        bars = event.dict_['data']
        self.on_bars(bars)

    def buy(self, price, volume, stop_price=EMPTY_FLOAT, stop=False, dt=None):
        """买开=OpenLong"""
        # self.strategyEngine.openLong(self.vtSymbol, price, volume)
        if not dt:
            dt = datetime.datetime.now()
        self.send_order(STRATEGY_ORDER_BUY, price, volume, stop_price, stop, dt)
        self.set_pos(self.pos + volume)

    def sell(self, price, volume, stop_price=EMPTY_FLOAT, stop=False, dt=None):
        """卖平=CloseLong"""
        # self.strategyEngine.closeLong(self.vtSymbol, price, volume)
        if not dt:
            dt = datetime.datetime.now()
        self.send_order(STRATEGY_ORDER_SELL, price, volume, stop_price, stop, dt)
        self.set_pos(self.pos - volume)

    def short(self, price, volume, stop_price=EMPTY_FLOAT, stop=False, dt=None):
        """卖开=OpenShort"""
        # self.strategyEngine.openShort(self.vtSymbol, price, volume)
        if not dt:
            dt = datetime.datetime.now()
        self.send_order(STRATEGY_ORDER_SHORT, price, volume, stop_price, stop, dt)
        self.set_pos(self.pos - volume)

    def cover(self, price, volume, stop_price=EMPTY_FLOAT, stop=False, dt=None):
        """买平=CloseShort"""
        # self.strategyEngine.closeShort(self.vtSymbol, price, volume)
        if not dt:
            dt = datetime.datetime.now()
        self.send_order(STRATEGY_ORDER_COVER, price, volume, stop_price, stop, dt)
        self.set_pos(self.pos + volume)

    def send_order(self, order_type, price, volume, stop_price=EMPTY_FLOAT, stop=False, dt=None):
        # print("""发送委托 from strategy""")
        ss = StrategySignal()
        ss.datetime = dt
        ss.symbol = self.symbol
        ss.name = self.instance_name
        ss.price = price
        ss.vol = volume
        ss.order_type = order_type
        ss.params = self.params
        ss.stop_price = stop_price

        now = datetime.now().strftime('%Y%m%d %H:%M:%S.%f')
        self.strategy_signals[now] = ss
        event = Event(event_type=EVENT_STRATEGY_SIGNAL + self.instance_name, dict_={'data': ss})

        self.event_engine.put(event)

    def req_log(self, content):
        log = f"{datetime.datetime.now().strftime('%Y%m%d %H%M%S')}:{self.instance_name}:{content}"
        self.event_engine.put(Event(event_type=EVENT_LOG, dict_={'data': log}))

    def _put_history_signals(self):
        """"""
        evt = Event(event_type=EVENT_STRATEGY_HISTORY_SIGNALS)
        evt.dict_['data'] = self.strategy_signals
        self.event_engine.put(evt)


if __name__ == '__main__':
    ed = datetime.datetime.now()
